﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DbTeleportáció
{
    /// <summary>
    /// Functions for interacting with files on the file system
    /// </summary>
    /// <remarks>
    /// -------------------------------------------Change Log---------------------------------------------
    /// 04/01/2016 - DCS - Created
    /// --------------------------------------------------------------------------------------------------
    /// </remarks>
    class FileMgr
    {
        private readonly Options _options;
        private const string _archiveExtension = "zip";

        /// <summary>
        /// Instantiates a new instance of the FileManager class using the provided command line arguments
        /// </summary>
        /// <param name="options"></param>
        public FileMgr(Options options)
        {
            _options = options;
        }

        /// <summary>
        /// Deletes all files from the FileDropDirectory specified in the command line arguments
        /// </summary>
        public void ClearFileDropDirectory()
        {
            Console.WriteLine($"Clearing file drop directory {_options.FileDropDirectory}...");

            if (Directory.Exists(_options.FileDropDirectory))
            {
                DirectoryInfo directory = new DirectoryInfo(_options.FileDropDirectory);

                foreach (FileInfo file in directory.GetFiles())
                {
                    Console.WriteLine($"Deleting file {file.Name}...");

                    try
                    {
                        file.Delete();
                    }
                    catch (Exception)
                    {
                        Environment.ExitCode = (int)ExitCodes.FailedToDeleteFilesInDropDirectory;
                        throw;
                    }

                    Console.WriteLine($"{file.Name} deleted.");
                }

                foreach (DirectoryInfo subDir in directory.GetDirectories())
                {
                    Console.WriteLine($"Deleting subdirectory {subDir.Name}...");

                    try
                    {
                        subDir.Delete(true);
                    }
                    catch (Exception)
                    {
                        Environment.ExitCode = (int)ExitCodes.FailedToDeleteDirectoriesInDropDirectory;
                        throw;
                    }

                    Console.WriteLine($"{subDir.Name} deleted.");
                }
            }
            else
            {
                Console.WriteLine($"Directory {_options.FileDropDirectory} does not exist.  Nothing to clear.");
            }
        }

        /// <summary>
        /// Creates the FileDropDirectory specified in the command line arguments
        /// </summary>
        public void CreateFileDropDirectory()
        {
            if (!Directory.Exists(_options.FileDropDirectory))
            {
                try
                {
                    Directory.CreateDirectory(_options.FileDropDirectory);
                }
                catch (Exception)
                {
                    Environment.ExitCode = (int)ExitCodes.FailedToCreateFileDropDirectory;
                    throw;
                }
            }
        }

        /// <summary>
        /// Compresses all files in the FileDropDirectory into an archive
        /// </summary>
        public void CompressExtractedData()
        {
            Console.WriteLine("Compressing exported data...");

            var archiveFile = Path.Combine(_options.FileDropDirectory, $"{_options.Database}.{_archiveExtension}");
            var uncompressedFiles = GetUncompressedFiles();

            try
            {
                using (MemoryStream stream = new MemoryStream())
                {
                    using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Create, true))
                    {
                        foreach (FileInfo file in uncompressedFiles)
                        {
                            archive.CreateEntryFromFile(file.FullName, file.Name);
                        }
                    }

                    using (FileStream zipFile = new FileStream(archiveFile, FileMode.Create))
                    {
                        stream.Seek(0, SeekOrigin.Begin);
                        stream.CopyTo(zipFile);
                    }
                }
            }
            catch (Exception)
            {
                Environment.ExitCode = (int)ExitCodes.FailedToCompressExtractedData;
                throw;
            }

            if (File.Exists(archiveFile))
            {
                Console.WriteLine($"Exported data compressed to {archiveFile}");
            }
            else
            {
                Environment.ExitCode = (int)ExitCodes.FailedToCompressExtractedData;
                Console.WriteLine($"Failed creating compressed file {archiveFile}");
            }
        }

        /// <summary>
        /// Removes (deletes) any files in the FileDropDirectory with the exception of compressed files
        /// </summary>
        public void DeleteUncompressedFiles()
        {
            var uncompressedFiles = GetUncompressedFiles();

            foreach (FileInfo file in uncompressedFiles)
            {
                try
                {
                    file.Delete();
                }
                catch (Exception)
                {
                    Environment.ExitCode = (int)ExitCodes.FailedToDeleteUncompressedFiles;
                    throw;
                }
            }
        }

        /// <summary>
        /// Returns all files in the FileDropDirectory with the exception of compressed archives (ZIP files)
        /// </summary>
        /// <returns>
        /// Collection of FileInfo objects representing any files in the FileDropDirectory with the 
        /// exception of compressed archives
        /// </returns>
        private IEnumerable<FileInfo> GetUncompressedFiles()
        {
            var directory = new DirectoryInfo(_options.FileDropDirectory);

            try
            {
                return directory.GetFiles().Where(f => !f.Extension.EndsWith(_archiveExtension, StringComparison.InvariantCultureIgnoreCase));
            }
            catch (Exception)
            {
                Environment.ExitCode = (int)ExitCodes.FailedToEnumerateUncompressedFiles;
                throw;
            }
        }
    }
}
